package utils.sl651;
/**
 * SL651协议CRC校验工具类
 * 
 * 实现符合SL651-2014标准的CRC校验算法
 */
public class SL651CrcUtil {
    
    // CRC16校验多项式
    private static final int CRC16_POLYNOMIAL = 0xA001;
    
    /**
     * 计算CRC16校验码
     * 
     * @param data 待校验的数据字节数组
     * @return CRC16校验码（4位十六进制字符串）
     */
    public static String calculateCrc16ForHex(byte[] data) {
        int crc = 0xFFFF;
        
        for (byte b : data) {
            crc ^= (b & 0xFF);
            
            for (int i = 0; i < 8; i++) {
                if ((crc & 0x0001) != 0) {
                    crc = (crc >> 1) ^ CRC16_POLYNOMIAL;
                } else {
                    crc = crc >> 1;
                }
            }
        }
        
        // 返回4位十六进制字符串，高位在前
        return String.format("%04X", crc);
    }
    
    /**
     * 计算字符串的CRC16校验码
     * 
     * @param data 待校验的十六进制字符串
     * @return CRC16校验码（4位十六进制字符串）
     */
    public static String calculateCrc16ForHex(String data) {
        return calculateCrc16ForHex(SL651CommonUtil.hexStringToByteArray(data));
    }

    /**
     * 为ASCII编码报文计算CRC16校验码
     *
     * @param asciiString ASCII编码的字符串
     * @return CRC16校验码（4位十六进制字符串）
     */
    public static String calculateCrc16ForAscii(String asciiString) {
        byte[] data = asciiString.getBytes();
        int crc = 0xFFFF;

        for (byte b : data) {
            crc ^= (b & 0xFF);
            for (int i = 0; i < 8; i++) {
                if ((crc & 0x0001) != 0) {
                    crc >>= 1;
                    crc ^= 0xA001;
                } else {
                    crc >>= 1;
                }
            }
        }

        return String.format("%04X", crc);
    }
    
    /**
     * 验证CRC校验码是否正确
     * 
     * @param data 原始数据
     * @param expectedCrc 期望的CRC校验码
     * @return 校验是否通过
     */
    public static boolean verifyCrcForHex(byte[] data, String expectedCrc) {
        String calculatedCrc = calculateCrc16ForHex(data);
        return calculatedCrc.equalsIgnoreCase(expectedCrc);
    }
    
    /**
     * 验证十六进制字符串的CRC校验码
     * 
     * @param data 原始十六进制字符串
     * @param expectedCrc 期望的CRC校验码
     * @return 校验是否通过
     */
    public static boolean verifyCrcForHex(String data, String expectedCrc) {
        String calculatedCrc = calculateCrc16ForHex(data);
        return calculatedCrc.equalsIgnoreCase(expectedCrc);
    }

    /**
     * 从完整报文中提取并验证CRC校验码
     *
     * @param fullMessage 完整的报文字符串
     * @return 校验是否通过
     */
    public static boolean verifyAscillMessageCrc(String fullMessage) {
        if (fullMessage == null || fullMessage.length() < 4) {
            return false;
        }

        // 提取CRC校验码（最后4位）
        String crcFromMessage = fullMessage.substring(fullMessage.length() - 4);

        // 提取待校验数据（除去最后4位CRC）
        String dataToVerify = fullMessage.substring(0, fullMessage.length() - 4);

        return verifyCrcForAscill(dataToVerify, crcFromMessage);
    }

    /**
     * 验证十六进制字符串的CRC校验码
     *
     * @param data 原始十六进制字符串
     * @param expectedCrc 期望的CRC校验码
     * @return 校验是否通过
     */
    public static boolean verifyCrcForAscill(String data, String expectedCrc) {
        String calculatedCrc = calculateCrc16ForAscii(data);
        return calculatedCrc.equalsIgnoreCase(expectedCrc);
    }

    /**
     * 从完整报文中提取并验证CRC校验码
     *
     * @param fullMessage 完整的报文字符串
     * @return 校验是否通过
     */
    public static boolean verifyHexMessageCrc(String fullMessage) {
        if (fullMessage == null || fullMessage.length() < 4) {
            return false;
        }

        // 提取CRC校验码（最后4位）
        String crcFromMessage = fullMessage.substring(fullMessage.length() - 4);

        // 提取待校验数据（除去最后4位CRC）
        String dataToVerify = fullMessage.substring(0, fullMessage.length() - 4);

        return verifyCrcForHex(dataToVerify, crcFromMessage);
    }
}